//*****************************************************************************
//* Foxit Digital Rights Management Library
//*
//* Foxit Software Inc.
//* Copyright(C) 2005-2010, all rights reserved.
//*
//* The following code is copyrighted and contains proprietary information
//* and trade secrets of Foxit Software Inc.
//*****************************************************************************
/**
 * @addtogroup FDRM
 * @{
 */

/**
 * @file
 * @brief Define basic interfaces, classes & functions of cryptograph.
 */

#ifndef _FDRM_CRYPTO
#define _FDRM_CRYPTO

//Classes defined in this header
class IFDRM_SeedProvider;
class IFDRM_KeyProvider;
	class CFDRM_KeyProvider;
class IFDRM_CryptorProvider;
	class CFDRM_CryptorProvider;
class IFDRM_Digest;
class IFDRM_Cryptor;

//*****************************************************************************
//* Seed provider
//*****************************************************************************
/**
 * @name Seed Provider
 */
/*@{*/

/**
 * @brief Seed provider. Provides a way to get a seed value.
 */
class IFDRM_SeedProvider : public CFDRM_Object
{
public:
	/** Retrieve a seed value. */
	virtual FX_DWORD	GetSeed() = 0;
};

/**
 * @brief Create a default seed provider.
 * @return Return an object pointer. Caller should call Release method when destroy this object.
 */
IFDRM_SeedProvider*	FDRM_SeedProvider_CreateDef();

/*@}*/ 

//*****************************************************************************
//* Key provider
//*****************************************************************************
/**
 * @name Key Provider
 */
/*@{*/

/**
 * @brief Key provider interface. Enumerates all sub keys.
 */
class IFDRM_KeyProvider : public CFDRM_Object
{
public:
	/**
	 * @brief	Get counter number of total sub keys.
	 * @return	Return the total number of sub keys.
	 */
	virtual FX_INT32	CountKeys() = 0;

	/**
	 * @brief	Retrieve the algorithm of a sub key.
	 * @param[in] nIndex		the index number of sub key.
	 * @param[out] bsTreatment	stores the retrieved treatment string.
	 * @return	If nIndex is valid and find the treatment, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetKeyTreatment(FX_INT32 nIndex, CFX_ByteString &bsTreatment) = 0;
	/**
	 * @brief	Retrieve the order of a sub key.
	 * @param[in] nIndex		the index number of sub key.
	 * @param[out] dwOrder		stores the retrieved order number.
	 * @return	If nIndex is valid and find the order, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetKeyOrder(FX_INT32 nIndex, FX_DWORD &dwOrder) = 0;
	/**
	 * @brief	Retrieve the version of a sub key.
	 * @param[in] nIndex		the index number of sub key.
	 * @param[out] dwVersion	stores the retrieved version number.
	 * @return	If nIndex is valid and find the version, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetKeyVersion(FX_INT32 nIndex, FX_DWORD &dwVersion) = 0;
	/**
	 * @brief	Retrieve the value of a sub key.
	 * @param[in] nIndex		the index number of sub key.
	 * @param[out] bsValue		stores the retrieved value string.
	 * @return	If nIndex is valid and find the value, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetKeyValue(FX_INT32 nIndex, CFDRM_ByteKeyString &bsValue) = 0;
};

/**
 * @brief Key provider class. Data class for convenient purpose.
 */
class CFDRM_KeyProvider : public IFDRM_KeyProvider
{
public:
	/** Default constructor */

	CFDRM_KeyProvider();
	/** virtual destructor, refer to CFDRM_Object */
	virtual ~CFDRM_KeyProvider();

	/**
	 * @brief	The following methods overrides the corresponding methods in IFDRM_KeyProvider.
	 *			Refer to the description in IFDRM_KeyProvider.
	 */
	virtual FX_INT32	CountKeys();
	virtual FX_BOOL		GetKeyTreatment(FX_INT32 nIndex, CFX_ByteString &bsTreatment);
	virtual FX_BOOL		GetKeyOrder(FX_INT32 nIndex, FX_DWORD &dwOrder);
	virtual FX_BOOL		GetKeyVersion(FX_INT32 nIndex, FX_DWORD &dwVersion);
	virtual FX_BOOL		GetKeyValue(FX_INT32 nIndex, CFDRM_ByteKeyString &bsValue);

	static CFX_ByteStringC		FDRM_KEYTREATMENT_1ST;
	static CFX_ByteStringC		FDRM_KEYTREATMENT_2ND;
	static CFX_ByteStringC		FDRM_KEYTREATMENT_3RD;
	/**
	 * @brief Add a sub key.
	 * @param[in] bsTreatment	key treatment string.
	 * @param[in] dwOrder		key order number.
	 * @param[in] dwVersion		key version number.
	 * @param[in] bsValue		key value string.
	 */
	void	AddKey(FX_BSTR bsTreatment, FX_DWORD dwOrder, FX_DWORD dwVersion, const CFDRM_ByteKeyString &bsValue);

protected:
	FX_LPVOID	m_pData;
};

/*@}*/ 

//*****************************************************************************
//* Cryptor provider
//*****************************************************************************
/**
 * @name Cryptor Provider
 */
/*@{*/

//macros for available cryptor parameter names
/**
 * @brief	BlockSize name, specifies the block size of data when encrypts or decrypts data.
 *			Block size must be multiple value of operator key size. 
 */
#define FDRM_CRYPTORPARAM_BlockSize		FX_BSTRC("BlockSize")

/**
 * @brief Cryptor provider interface. Provides cryptor info.
 */
class IFDRM_CryptorProvider : public CFDRM_Object
{
public:
	/**
	 * @brief	Retrieve operator used in cryptor.
	 * @param[out] op		stores the retrieved operator.
	 */
	virtual void		GetOperator(CFDRM_Operator &op) const = 0;

	/**
	 * @brief	Get the count number of cryptor parameters.
	 * @return	Return the number of cryptor parameters.
	 */
	virtual FX_INT32	CountCryptorParams() const = 0;
	/**
	 * @brief	Retrieve parameter name.
	 * @param[in] nIndex		the index number of parameter.
	 * @param[out] bsName		stores the retrieved parameter name string.
	 * @return	If nIndex is valid and find the name, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetCryptorParamName(FX_INT32 nIndex, CFX_ByteString &bsName) const = 0;
	/**
	 * @brief	Retrieve parameter value by position index number.
	 * @param[in] nIndex		the index number of parameter.
	 * @param[out] bsValue		stores the retrieved parameter value string.
	 * @return	If nIndex is valid and find the value, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetCryptorParamValue(FX_INT32 nIndex, CFX_ByteString &bsValue) const = 0;
	/**
	 * @brief	Find and retrieve parameter value by name.
	 * @param[in] bsName		parameter name which is used to find the value.
	 * @param[out] bsValue		stores the retrieved parameter value string.
	 * @return	If bsName is valid and find the value, return TRUE, or FALSE if not find or meet errors.
	 */
	virtual FX_BOOL		GetCryptorParamValue(FX_BSTR bsName, CFX_ByteString &bsValue) const = 0;
};

/**
 * @brief Cryptor provider class. Data class for convenient purpose.
 */
class CFDRM_CryptorProvider : public IFDRM_CryptorProvider
{
public:
	/** Default constructor */
	CFDRM_CryptorProvider();
	/** virtual destructor, refer to CFDRM_Object */
	virtual ~CFDRM_CryptorProvider();

	/**
	 * @brief	The following methods overrides the corresponding methods in IFDRM_CryptorProvider.
	 *			Refer to the description in IFDRM_CryptorProvider.
	 */
	virtual void		GetOperator(CFDRM_Operator &op) const;
	virtual FX_INT32	CountCryptorParams() const;
	virtual FX_BOOL		GetCryptorParamName(FX_INT32 nIndex, CFX_ByteString &bsName) const;
	virtual FX_BOOL		GetCryptorParamValue(FX_INT32 nIndex, CFX_ByteString &bsValue) const;
	virtual FX_BOOL		GetCryptorParamValue(FX_BSTR bsName, CFX_ByteString &bsValue) const;

	/**
	 * @brief Set cryptor algorithm string.
	 * @param[in] op	operator to be set.
	 */
	void		SetOperator(const CFDRM_Operator &op);

	/**
	 * @brief Set a cryptor parameter.
	 * @param[in] bsName	parameter name string.
	 * @param[in] bsValue	parameter value string.
	 */
	void		SetCryptorParam(FX_BSTR bsName, FX_BSTR bsValue);

	/** @brief	Get/Set block size. This is shortcut for FDRM_CRYPTORPARAM_BlockSize. */
	FX_DWORD	GetBlockSize() const;
	void		SetBlockSize(FX_DWORD dwBlockSize);

protected:
	FX_LPVOID	m_pData;
};

/*@}*/ 

//*****************************************************************************
//* Digest algorithm
//*****************************************************************************
/**
 * @name Digest algorithm
 * Only FDRM_OPERATOR_MD5_128, FDRM_OPERATOR_SHA1_160, FDRM_OPERATOR_SHA2_256 are available.
 */
/*@{*/

/**
 * @brief Digest/Hash algorithm.
 */
class IFDRM_Digest : public CFDRM_Object
{
public:
	/**
	 * @brief Start or initialize a digest operator.
	 * @param[in] op	digest operator, limited to FDRM_OPERATOR_MD5_128, FDRM_OPERATOR_SHA1_160, FDRM_OPERATOR_SHA2_256.
	 * @return	Return non-negative value if successful;
	 *			Return -1 if initialization is error;
	 *			Return -2 if digest operator is not permitted;
	 *			Return -3 if digest operator is error;
	 *			Return other negative value if any error occurs.
	 */
	virtual FX_INT32	StartDigest(const CFDRM_Operator &op) = 0;

	/**
	 * @brief	Generate digest value in progressive mode, the instance of this interface should contain a valid IFX_FileRead object.
	 * @param[in] pPause	a pause object if need progressive control, or pass NULL for normal control.
	 * @return	Return any positive value less than 100 if the method is paused;
	 *			Return 100 or a positive value greater than 100 if the method finishes;
	 *			Return any negative value if any error occurs.
	 */
	virtual FX_INT32	DoDigest(IFX_Pause *pPause = NULL) = 0;

	/**
	 * @brief	Generate digest value for buffer data. This method can be called sequentially for a long data block.
	 * @param[in] pBuffer	points to memory buffer.
	 * @param[in] dwSize	specifies the buffer data size.
	 * @return	Return non-negative value if successful;
	 *			Return any negative value if any error occurs.
	 */
	virtual FX_INT32	DoDigest(FX_LPCBYTE pBuffer, FX_DWORD dwSize) = 0;

	/**
	 * @brief	Stop the digest generation.
	 */
	virtual void		EndDigest() = 0;

	/**
	 * @brief	Get the digest value.
	 * @param[out] bsDigest	stores the retrieved digest value, the length of digest value is related to the operator.
	 * @return	If there is available digest value, returns TRUE, or returns FALSE for any error.
	 */
	virtual FX_BOOL		GetDigest(CFDRM_ByteKeyString &bsDigest) = 0;
};

/**
 * @brief Create an instance of IFDRM_Digest interface.
 * @param[in] pSrc	points to IFX_FileRead stream object. If it's not NULL, generate digest value under progressive mode, or generate from buffer.
 * @return Return an object pointer. Caller should call Release method to destroy this object.
 */
IFDRM_Digest*	FDRM_Digest_Create(IFX_FileRead *pSrc = NULL);

/**
 * @brief Generate digest value from a stream directly.
 * @param[in] op			the digest operator.
 * @param[in] pSrc			points to IFX_FileRead stream object.
 * @param[out] bsDigest		stores the generated digest value. The length is related to the digest operator.
 * @return	Return non-negative value if successful;
 *			Return -1 if initialization is error;
 *			Return -2 if digest operator is not permitted;
 *			Return -3 if digest operator is error;
 *			Return -4 if source stream is error or cannot read data from it;
 *			Return other negative value if any error occurs.
 */
FX_INT32		FDRM_Digest_Generate(const CFDRM_Operator &op, IFX_FileRead *pSrc, CFDRM_ByteKeyString &bsDigest);

/**
 * @brief Generate digest value from a memory buffer directly.
 * @param[in] op			the digest operator.
 * @param[in] pBuffer		points to memory buffer.
 * @param[in] dwSize		specifies the buffer data size.
 * @param[out] bsDigest		stores the generated digest value. The length is related to the digest algorithm.
 * @return	Return non-negative value if successful;
 *			Return -1 if initialization is error;
 *			Return -2 if digest operator is not permitted;
 *			Return -3 if digest operator is error;
 *			Return -4 if the memory buffer is error or cannot read data from it;
 *			Return other negative value if any error occurs.
 */
FX_INT32		FDRM_Digest_Generate(const CFDRM_Operator &op, FX_LPCBYTE pBuffer, FX_DWORD dwSize, CFDRM_ByteKeyString &bsDigest);

/*@}*/

//*****************************************************************************
//* Cryptor
//*****************************************************************************
/**
 * @name Cryptor - crypto operator
 * Only FDRM_OPERATOR_ARC4_XXX, FDRM_OPERATOR_AES_XXX are available.
 */
/*@{*/

/**
 * @brief Crypto operator
 */
class IFDRM_Cryptor : public CFDRM_Object
{
public:
	/**
	 * @brief	Initialize cryptor.
	 * @param[in] bsKey			cryptor key, it should match to the current cryptor.
	 * @param[in] bsVector		cryptor initial vector, only used in FDRM_OPERATOR_AES_XXX.
	 * @param[in] dwBlockSize	block size which is used to align data block with key size.
	 *							If it's 0, means default block alignment is used.
	 * @return	Return a non-negative value for getting ready;
	 *			Return -1 if crypto operator is not permitted;
	 *			Return -2 if crypto key does not match or is error;
	 *			Return -3 if initialization is error;
	 *			Return other negative value if any other error occurs.
	 */
	virtual FX_INT32	InitCryptor(const CFDRM_ByteKeyString &bsKey, const CFDRM_ByteKeyString &bsVector, FX_DWORD dwBlockSize = 0) = 0;

	/**
	 * @brief	Retrieve the current block size, updated by dwBlockSize value when call InitCryptor method.
	 * @return	Return the block size used internally.
	 */
	virtual FX_DWORD	GetBlockSize() = 0;

	/**
	 * @brief	Encrypt/decrypt data from source buffer into destination buffer, block size is not used in this method.
	 * @param[in] pSrc			the source buffer, it can be identical to pDst.
	 * @param[out] pDst			the destination buffer, it can be identitcal to pSrc.
	 * @param[in] dwSize		specifies the buffer size, pSrc and pDst should have the same size. Buffer size should be multiple to the key size.
	 * @param[in] bEncryption	specifies to do encryption or decryption, if it's TRUE(default), encryption is applied.
	 * @return	Return a non-negative value if successful;
	 *			Return -1 if crypto operator is not permitted;
	 *			Return -2 if crypto key does not match or is error;
	 *			Return -3 if initialization is error;
	 *			Return -4 if pSrc or pDst is error, or data cannot be used;
	 *			Return -5 dwSize is not aligned to the key size.
	 *			Return other negative value if any other error occurs.
	 */
	virtual FX_INT32	DoCryptor(FX_LPCBYTE pSrc, FX_LPBYTE pDst, FX_DWORD dwSize, FX_BOOL bEncryption = TRUE) = 0;

	/**
	 * @brief	Start cryptor, this method initializes the cryptor status in progressive mode.
	 * @param[in] pSrc			the source data stream.
	 * @param[in] pDst			the destination data stream.
	 * @param[in] bEncryption	specifies to do encryption or decryption, if it's TRUE(default), encryption is applied.
	 *							When bEncryption is TRUE, the destination data size may be larger than the source data size
	 *							if the current crypto operater is FDRM_OPERATOR_AES_XXX. So when bEncryption is FALSE,
	 *							the destination size may be smaller than the source size. pDst should have enough space.
	 *							To get the final destination size, call IFX_FileWrite::GetSize method for pDst.
	 * @return	Return a non-negative value for getting ready;
	 *			Return -1 if crypto operator is not permitted;
	 *			Return -2 if crypto key does not match or is error;
	 *			Return -3 if initialization is error;
	 *			Return -4 if source data stream cannot be used;
	 *			Return -5 if destination data stream is not ready or cannot write data;
	 *			Return other negative value if any error occurs.
	 */
	virtual FX_INT32	StartCryptor(IFX_FileRead *pSrc, IFX_FileWrite *pDst, FX_BOOL bEncryption = TRUE) = 0;

	/**
	 * @brief	Do cryptor in progressive mode.
	 * @param[in] pPause	a pause object if need progressive control, or pass NULL for normal control.
	 * @return	Return any positive value which is less than 100 if the cryptor is paused;
	 *			Return 100 or a positive value greater than 100 if the cryptor finishes;
	 *			Return any negative value if any error occurs.
	 */
	virtual FX_INT32	DoCryptor(IFX_Pause *pPause = NULL) = 0;
};

/**
 * @brief	Create an instance of crypto operator.
 * @param[in] opCryptor		specifies crypto operator object, available cryptors are limited to FDRM_OPERATOR_ARC4_XXX, FDRM_OPERATOR_AES_XXX.
 * @return	Return the instance object of cryptor. Return NULL if meets any error.
 */
IFDRM_Cryptor*	FDRM_Cryptor_Create(const CFDRM_Operator &opCryptor);

/*@}*/

#endif //_FDRM_CRYPTO

/** @} */
